<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ganttExp2-手动改变画布尺寸</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            overflow: auto;
        }

        .gantt-box {
            position: relative;
            padding: 20px; /* 添加20px的外扩 */
            box-sizing: border-box; /* 确保padding不会增加元素的总宽度和高度 */
            width: 100%;
            height: 100%;
        }

        .cvs1 {
            width: 100%;
            height: 100%;
            border: 1px solid red;
        }

        .zoom-controls {
            position: absolute;
            top: 10px;
            right: 10px;
            padding: 5px;
            border: 1px solid #ccc;
            background-color: rgba(255, 255, 255, 0.5);
            font-size: 14px; /* 调整字体大小以便于阅读 */
            z-index: 10;
        }

        .zoom-controls input {
            width: 50px;
            margin: 0 5px;
        }
    </style>

    <script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.min.js"></script>
    <script type="text/javascript" src="https://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luxon@1.27.0/build/global/luxon.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script>
    <script type="module">
        // 初始化 DataGrid
        const initTasks = [
            {
                name: '框柱安装1组', color: 'rgba(255, 99, 132, 0.2)',
                meshs: [
                    { name: '1', timestamp: 1676248341000 },
                    { name: '2', timestamp: 1676255541000 },
                    { name: '3', timestamp: 1676262741000 },
                    { name: '4', timestamp: 1676269941000 },
                    { name: '5', timestamp: 1676277141000 },
                    { name: '6', timestamp: 1676284341000 },
                    { name: "7", timestamp: 1676334741000 },
                    {
                        "name": "8",
                        "timestamp": 1676341941000
                    },
                    {
                        "name": "9",
                        "timestamp": 1676349141000
                    },
                    {
                        "name": "10",
                        "timestamp": 1676356341000
                    },
                    {
                        "name": "11",
                        "timestamp": 1676363541000
                    },
                    {
                        "name": "12",
                        "timestamp": 1676370741000
                    }
                ]
            },
            {
                name: '框柱安装2组', color: 'rgba(54, 162, 235, 0.2)',
                meshs: [
                    { name: '13', timestamp: 1676421141000 },
                    { name: '14', timestamp: 1676431141000 },
                    { name: '15', timestamp: 1676441141000 },
                    { name: '16', timestamp: 1676451141000 },
                    { name: '17', timestamp: 1676461141000 },
                    { name: '18', timestamp: 1676471141000 },
                    { name: '19', timestamp: 1676334741000 },
                    { name: '20', timestamp: 1676344741000 },
                    { name: '21', timestamp: 1676354741000 },
                    { name: '22', timestamp: 1676364741000 },
                    { name: '23', timestamp: 1676374741000 },
                    { name: '24', timestamp: 1676384741000 }
                ]
            },
            {
                name: '框柱安装3组', color: 'rgba(255, 206, 86, 0.2)',
                meshs: [
                    { name: '25', timestamp: 1676593941000 },
                    { name: '26', timestamp: 1676603941000 },
                    { name: '27', timestamp: 1676613941000 },
                    { name: '28', timestamp: 1676623941000 },
                    { name: '29', timestamp: 1676633941000 },
                    { name: '30', timestamp: 1676643941000 },
                    { name: '31', timestamp: 1676513941000 },
                    { name: '32', timestamp: 1676523941000 },
                    { name: '33', timestamp: 1676533941000 },
                    { name: '34', timestamp: 1676543941000 },
                    { name: '35', timestamp: 1676553941000 },
                    { name: '36', timestamp: 1676563941000 }
                ]
            }
        ];

        let initialTasks = initTasks.map(task => {
            return updateTaskDates(task);
        });
        let tasksData = [];

        function updateTaskDates(task) {
            if (!task.meshs || task.meshs.length === 0) {
                task.StartDate = '';
                task.Duration = '';
                return;
            }

            const dates = task.meshs.map(mesh => mesh.timestamp);
            const minDate = luxon.DateTime.fromMillis(
                dates.reduce((min, date) => date < min ? date : min)
            );
            const maxDate = luxon.DateTime.fromMillis(
                dates.reduce((max, date) => date > max ? date : max)
            );

            task.StartDate = minDate.toISODate();
            task.Duration = maxDate.diff(minDate, 'days').days;
            return task;
        }

        $(document).ready(function () {
            // 初始化甘特图
            const ctx = document.getElementById('ganttChart').getContext('2d');
            let ganttChart;

            function initGanttChart(tasks) {
                if (ganttChart) {
                    ganttChart.destroy(); // 销毁旧的图表实例
                }

                ganttChart = new Chart(ctx, {
                    type: 'bar',
                    data: {
                        labels: tasks.map(task => task.name),
                        datasets: [{
                            label: '任务进度',
                            data: tasks.map(task => ({})),
                            backgroundColor: [],
                            borderColor: [],
                            borderWidth: 0
                        }]
                    },
                    options: {
                        indexAxis: 'y',
                        aspectRatio: false,    // 宽度自适应
                        scales: {
                            x: {
                                type: 'time',
                                time: {
                                    unit: 'day',
                                    tooltipFormat: 'yyyy-MM-dd'
                                },
                                min: getMinDate(tasks),
                                max: getMaxDate(tasks)
                            },
                            y: {
                                ticks: {
                                    autoSkip: false
                                }
                            }
                        },
                        plugins: {
                            legend: {
                                display: false
                            },
                            title: {
                                display: true,
                                text: '横道图示例'
                            }
                        },
                        elements: {
                            bar: {
                                display: false
                            }
                        }
                    },
                    plugins: [{
                        id: 'customGantt',
                        afterDraw: function (chart) {
                            const ctx = chart.ctx;
                            const xScale = chart.scales.x;
                            const yScale = chart.scales.y;

                            tasks.forEach((task, index) => {
                                const startDate = task.meshs.reduce((min, mesh) => {
                                    const start = luxon.DateTime.fromMillis(mesh.timestamp);
                                    return start < min ? start : min;
                                }, luxon.DateTime.fromMillis(task.meshs[0].timestamp));

                                const endDate = startDate.plus({ days: task.Duration });

                                const x = xScale.getPixelForValue(startDate);
                                const y = yScale.getPixelForValue(task.name) - 12;
                                const width = xScale.getPixelForValue(endDate) - x;
                                const height = 24;

                                ctx.fillStyle = task.color;
                                ctx.fillRect(x, y, width, height);

                                ctx.fillStyle = '#000';
                                ctx.font = '12px Arial';
                                ctx.textAlign = 'center';
                                ctx.fillText(task.name, x + width / 2, y + height / 2 + 4);
                            });
                        }
                    }]
                });
            }

            // 获取任务的最小开始时间
            function getMinDate(tasks) {
                return tasks.reduce((min, task) => {
                    const start = luxon.DateTime.fromISO(task.StartDate).minus({ days: 1 });
                    return start < min ? start : min;
                }, luxon.DateTime.fromISO(tasks[0].StartDate).minus({ days: 1 })).toISODate();
            }

            // 获取任务的最大结束时间
            function getMaxDate(tasks) {
                return tasks.reduce((max, task) => {
                    const end = luxon.DateTime.fromISO(task.StartDate).plus({ days: task.Duration + 2 });
                    return end > max ? end : max;
                }, luxon.DateTime.fromISO(tasks[0].StartDate).plus({ days: tasks[0].Duration + 2 })).toISODate();
            }

            // 初始化甘特图和时间轴
            initGanttChart(initialTasks);

            // 初始化缩放控件
            const ganttBox = document.querySelector('.gantt-box');
            const ganttChart = document.getElementById('ganttChart');
            const widthZoomInput = document.getElementById('widthZoomInput');
            const heightZoomInput = document.getElementById('heightZoomInput');

            // 设置初始值
            widthZoomInput.value = 100;
            heightZoomInput.value = 100;

            // 更新画布大小
            function updateCanvasSize() {
                const widthPercentage = parseFloat(widthZoomInput.value) / 100;
                const heightPercentage = parseFloat(heightZoomInput.value) / 100;

                ganttChart.style.width = `${widthPercentage * 100}%`;
                ganttChart.style.height = `${heightPercentage * 100}%`;

                // 重新渲染图表
                ganttChart.width = ganttChart.offsetWidth;
                ganttChart.height = ganttChart.offsetHeight;
                ganttChart.getContext('2d').clearRect(0, 0, ganttChart.width, ganttChart.height);
                initGanttChart(tasksData);
            }

            // 绑定输入框的 change 事件
            widthZoomInput.addEventListener('change', updateCanvasSize);
            heightZoomInput.addEventListener('change', updateCanvasSize);

            // 绑定按钮的点击事件
            document.getElementById('widthZoomIn+').addEventListener('click', () => {
                widthZoomInput.value = Math.min(200, parseFloat(widthZoomInput.value) + 10);
                updateCanvasSize();
            });

            document.getElementById('widthZoomIn-').addEventListener('click', () => {
                widthZoomInput.value = Math.max(10, parseFloat(widthZoomInput.value) - 10);
                updateCanvasSize();
            });

            document.getElementById('heightZoomIn+').addEventListener('click', () => {
                heightZoomInput.value = Math.min(200, parseFloat(heightZoomInput.value) + 10);
                updateCanvasSize();
            });

            document.getElementById('heightZoomIn-').addEventListener('click', () => {
                heightZoomInput.value = Math.max(10, parseFloat(heightZoomInput.value) - 10);
                updateCanvasSize();
            });
        });
    </script>
</head>

<body>
    <div class="gantt-box">
        <canvas id="ganttChart" class="cvs1"></canvas>
        <!-- 添加画布缩放控件 -->
        <div class="zoom-controls" id="zoomControls">
            <span>宽度缩放：</span>
            <button id="widthZoomIn+">+</button>
            <input type="text" size="5" id="widthZoomInput" value="100" />
            <button id="widthZoomIn-">-</button><br><br>
            <span>高度缩放：</span>
            <button id="heightZoomIn+">+</button>
            <input type="text" size="5" id="heightZoomInput" value="100" />
            <button id="heightZoomIn-">-</button>
        </div>
    </div>
</body>

</html>